package com.michaelbulava.TFS.vcs;

import com.intellij.openapi.Disposable;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vcs.FilePath;
import com.intellij.openapi.vcs.FileStatus;
import com.intellij.openapi.vcs.changes.Change;
import com.intellij.openapi.vcs.changes.ChangeListManager;
import com.intellij.openapi.vfs.*;
import com.michaelbulava.TFS.log.FileLogger;
import com.michaelbulava.TFS.tasks.BackgroundableTask;
import com.michaelbulava.TFS.tasks.vc.CheckoutFileIfNeededTask;
import com.michaelbulava.TFS.vcs.exceptions.NotConnectedToTFS;
import com.michaelbulava.TFS.vcs.exceptions.TFSException;
import com.michaelbulava.TFS.vcs.internal.WorkstationHelper;
import com.michaelbulava.TFS.vcs.utils.TFSFileUtil;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.PendingChange;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.PendingSet;
import com.microsoft.tfs.core.clients.versioncontrol.soapextensions.Workspace;
import com.microsoft.tfs.core.clients.versioncontrol.specs.ItemSpec;
import org.jetbrains.annotations.NotNull;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Created by MichaelA on 9/29/2015.
 */
public class FileChangeListener implements VirtualFileListener {
    private static final Logger log = FileLogger.getInstance(FileChangeListener.class);
    private final Project myProject;

    public FileChangeListener(Project project) {
        this.myProject = project;
    }

    private boolean handleFile(VirtualFile file){
        return (TFSVcs.isUnderTFS(file, myProject) && !TFSVcs.isIgnored(myProject, file));
    }
    /**
     * Fired before the change of a name or writable status of a file is processed.
     *
     * @param event the event object containing information about the change.
     */
    @Override
    public void beforePropertyChange(@NotNull VirtualFilePropertyEvent event) {
        if (handleFile(event.getFile())) {
            log.info(MessageFormat.format("beforePropertyChanged fired on '{0}', Property name: {1}  Old Value: '{2}' New Value: '{3}'",
                    new Object[]{
                            event.getFile().getPath(),
                            event.getPropertyName(),
                            event.getOldValue(),
                            event.getNewValue()
                    }));
        }
    }

    /**
     * Fired when a virtual file is renamed from within IDEA, or its writable status is changed.
     * For files renamed externally, {@link #fileCreated} and {@link #fileDeleted} events will be fired.
     *
     * @param event the event object containing information about the change.
     */
    @Override
    public void propertyChanged(VirtualFilePropertyEvent event) {
        if (handleFile(event.getFile())) {
            log.info(MessageFormat.format("propertyChanged fired on '{0}', Property name: {1}  Old Value: '{2}' New Value: '{3}'",
                    new Object[]{
                            event.getFile().getPath(),
                            event.getPropertyName(),
                            event.getOldValue(),
                            event.getNewValue()
                    }));
        }
    }

    /**
     * Fired before the change of contents of a file is processed.
     *
     * @param event the event object containing information about the change.
     */
    @Override
    public void beforeContentsChange(VirtualFileEvent event) {
        if (handleFile(event.getFile())){
            log.info(MessageFormat.format("beforeContentsChanged fired on {0}",
                    new Object[]{event.getFile().getPath()}));

        }
    }

    /**
     * Fired when the contents of a virtual file is changed.
     *
     * @param event the event object containing information about the change.
     */
    @Override
    public void contentsChanged(VirtualFileEvent event) {
//        if (!event.isFromSave())
//            return;

        if (handleFile(event.getFile())){
            log.info(MessageFormat.format("contentsChanged fired on {0}",
                    new Object[]{event.getFile().getPath()}));
            CheckoutFileIfNeededTask task = new CheckoutFileIfNeededTask(myProject, event.getFile());
            ProgressManager.getInstance().run(task);
//            ChangeListManager changeListManager = ChangeListManager.getInstance(this.myProject);
//            Change change = changeListManager.getChange(event.getFile());
//            if (change != null){
//                FileStatus status = change.getFileStatus();
//                if (status == FileStatus.HIJACKED || status == FileStatus.NOT_CHANGED ||
//                        status == FileStatus.UNKNOWN || status == FileStatus.NOT_CHANGED_IMMEDIATE ||
//                        status == FileStatus.NOT_CHANGED_RECURSIVE) {
//
//                }
//            } else {
//                log.info("null Change.");
////                try {
////                    Workspace workspace = TFSVcs.getInstance(myProject).getWorkspaceForFile(event.getFile());
////                    PendingSet pendingSet = workspace.getPendingChanges(TFSFileUtil.getItemSpec(myProject,
////                            workspace, event.getFile()), false);
////                    if (pendingSet.getPendingChanges().length == 0){
////                        //TODO perform checkout.
////
////                    }
////                } catch (NotConnectedToTFS notConnectedToTFS) {
////                    notConnectedToTFS.printStackTrace();
////                }
//            }

        }
//        try {
//
//            Workspace workspace = TFSVcs.getInstance(myProject).getWorkspaceForFile(event.getFile());
//            ItemSpec[] itemSpecs = TFSFileUtil.getItemSpec(myProject, workspace, event.getFile());
//            PendingChange[] pendingChanges = workspace.getPendingChanges(itemSpecs, false).getPendingChanges();
//            for(PendingChange change : pendingChanges){
//
//            }
//        } catch (NotConnectedToTFS notConnectedToTFS) {
//            notConnectedToTFS.printStackTrace();
//        }
    }

    /**
     * Fired when a virtual file is created. This event is not fired for files discovered during initial VFS initialization.
     *
     * @param event the event object containing information about the change.
     */
    @Override
    public void fileCreated(final VirtualFileEvent event) {
        if (handleFile(event.getFile())){
            log.info(MessageFormat.format("fileCreate fired on {0}",
                    new Object[]{event.getFile().getPath()}));

            final BackgroundableTask task = new BackgroundableTask(myProject, "Adding file", false) {
                @Override
                protected boolean runInBackground() {
                    return true;
                }

                @Override
                public void run(@NotNull ProgressIndicator progressIndicator) {
                    TFSVcs.getInstance(myProject).getCheckinEnvironment()
                            .scheduleUnversionedFilesForAddition(Arrays.asList(new VirtualFile[] { event.getFile() }));
                }
            };

            ProgressManager.getInstance().run(task);
        }
    }

    /**
     * Fired before the deletion of a file is processed.
     *
     * @param event the event object containing information about the change.
     */
    @Override
    public void beforeFileDeletion(VirtualFileEvent event) {
        if (handleFile(event.getFile())) {
            log.info(MessageFormat.format("beforeFileDeleted fired on {0}",
                    new Object[]{event.getFile().getPath()}));

        }
    }

    /**
     * Fired when a virtual file is deleted.
     *
     * @param event the event object containing information about the change.
     */
    @Override
    public void fileDeleted(VirtualFileEvent event) {
        if (handleFile(event.getFile())) {
            log.info(MessageFormat.format("fileDeleted fired on {0}",
                    new Object[]{event.getFile().getPath()}));
        }
    }

    /**
     * Fired before the movement of a file is processed.
     *
     * @param event the event object containing information about the change.
     */
    @Override
    public void beforeFileMovement(VirtualFileMoveEvent event) {
        if (handleFile(event.getFile())) {
            log.info(MessageFormat.format("beforeFileMoved fired on {0}, OldParent: {1} New Parent: {1}",
                    new Object[]{
                            event.getFile().getPath(),
                            event.getOldParent().getPath(),
                            event.getNewParent().getPath()
                    }));
        }
    }

    /**
     * Fired when a virtual file is moved from within IDEA.
     *
     * @param event the event object containing information about the change.
     */
    @Override
    public void fileMoved(VirtualFileMoveEvent event) {
        if (handleFile(event.getFile())) {
            log.info(MessageFormat.format("fileMoved fired on {0}, OldParent: {1} New Parent: {1}",
                    new Object[]{
                            event.getFile().getPath(),
                            event.getOldParent().getPath(),
                            event.getNewParent().getPath()
                    }));
        }
    }

    /**
     * Fired when a virtual file is copied from within IDEA.
     *
     * @param event the event object containing information about the change.
     */
    @Override
    public void fileCopied(VirtualFileCopyEvent event) {
        if (handleFile(event.getFile())) {
            log.info(MessageFormat.format("fileCopied fired on {0} OriginalFile: {1}",
                    new Object[]{
                            event.getFile().getPath(),
                            event.getOriginalFile()
                    }));
        }
    }


}